package com.ms.game.invitefriend;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.ms.game.invitefriend.bin.InviteCodeType;
import com.ms.game.invitefriend.db.PreparedDistributorInviteCodeModel;
import com.xpec.c4.db.hibernate.manager.HibernateManager;
import com.xpec.c4.game.system.InitData;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.game.utility.GameUtility;

public class CreatePreparedDistributorInviteCodes {
	
	public static void main(String[] args) {
		
		Long number = Long.parseLong(args[0]);
		System.setProperty("log4j.configurationFile", "./config/log4j2.xml");
		InitData.initAll();
		GUIDFactory.setWorldId(1);
		GUIDFactory.setProcessId(1);
		create(number);
	}
	
	
	public static void create(Long number) {
		
		int inviteCodeLength = InviteCodeType.DISTRIBUTOR_INVITE_CODE.getRandomLen() + InviteCodeType.DISTRIBUTOR_INVITE_CODE.getTimeLen();
		int[] inviteCodeArray = new int[inviteCodeLength];

		Session session = HibernateManager.getSession();
		//取經銷商的
		Query query = session.createQuery("Select inviteCode From DistributorInviteCodesModel");
		List<String> _onlineInviteCodes = (List<String>) query.list();
		HashSet<String> onlineInviteCodes = new HashSet<String>(_onlineInviteCodes);
		
		
		session.clear();
		//取預產的
		query = session.createQuery("Select count(i) From PreparedDistributorInviteCodeModel i");
		Long preCount = (Long)query.uniqueResult();

		
		session.clear();
		SQLQuery sqlQuery = session.createSQLQuery("ALTER TABLE pre_distributor_invite_codes AUTO_INCREMENT = :NUM");
		sqlQuery.setParameter("NUM", preCount.intValue());
		sqlQuery.executeUpdate();
		session.clear();
		
		HashSet<String> inviteCodes = new HashSet<String>();
		Transaction tx = session.getTransaction();
		
		int saveCnt = 0;
		PreparedDistributorInviteCodeModel model = null;
		while (inviteCodes.size() < number) {
			
			for (int i = 0; i < inviteCodeArray.length; i++) {
				inviteCodeArray[i] = GameUtility.randomInt(0, InviteCodeGen.keysMap27.length - 1);
			}
			
			//替換成
			int length = GameUtility.randomInt(0, inviteCodeArray.length -1);
			inviteCodeArray[length] = inviteCodeLength;

			if (isConsecutive(inviteCodeArray, 5)) {
				continue;
			}

			if (isNotRepeating(inviteCodeArray, 3)) {
				continue;
			}
			
			StringBuilder inviteCodeBuilder = new StringBuilder();
			for (int num : inviteCodeArray) {
				if(num == inviteCodeArray.length) {
					inviteCodeBuilder.append(InviteCodeProcessor.DISTRIBUTOR_INVITE_CODE_IDENTIFY);
				}else{
					inviteCodeBuilder.append(InviteCodeGen.keysMap27[num]);
				}
			}
			String inviteCode = inviteCodeBuilder.toString();

			//目前產出中的
			if (inviteCodes.contains(inviteCode)) {
				continue;
			}

			//目前經銷商table中的
			if (onlineInviteCodes.contains(inviteCode)) {
				continue;
			}

			inviteCodes.add(inviteCode);

			if (saveCnt == 0) {
				tx.begin();
			}
			
			// 存入 log db
			try {
				model = new PreparedDistributorInviteCodeModel();
				model.setInviteCode(inviteCode);
				session.save(model);
				session.flush();

				// 暫停一下讓出 cpu 資源
				Thread.sleep(1);
			} catch (Exception e1) {
				continue;
			}

			saveCnt++;
			
			if (saveCnt % 100 == 0) {
				try {
					
					tx.commit();
					session.clear();
				} catch (HibernateException e) {
					tx.rollback();
				}
				saveCnt = 0;
			}
		}
		
		if (saveCnt > 0) {
			try {
				tx.commit();
				session.clear();
			} catch (HibernateException e) {
				tx.rollback();
			}
		}
		HibernateManager.endSession();
	}
	
	private static boolean isConsecutive(int[] column, int length) {
		int count = 0, num = 0;

		for (int i = 0; i < column.length; i++) {
			if (i == 0) {
				num = column[i];
				count++;
			} else {
				if (num == column[i]) {
					count++;
				} else {
					num = column[i];
					count = 1;
				}
			}

			if (count >= length) {
				return true;
			}
		}
		return false;
	}

	private static boolean isNotRepeating(int[] column, int length) {
		ArrayList<Integer> testList = new ArrayList<Integer>();

		for (int integer : column) {
			if (testList.contains(integer)) {
				continue;
			}
			testList.add(integer);
		}

		if (testList.size() > length) {
			return false;
		}

		return true;
	}

}
